package br.com.ac.fatureweb.integration.utilitary;

import java.math.BigDecimal;
import java.math.RoundingMode;
import java.text.DecimalFormat;
import java.text.DecimalFormatSymbols;
import java.text.NumberFormat;
import java.util.Locale;

public final class NumberUtils {

	/**
	 * Truncar um valor passado com parâmetro, será 0 (zero) caso o valor
	 * passado seja nulo. O valor retornado será com duas casas decimais.
	 *
	 * @param value
	 *            Valor informado.
	 * @param typeDecimal
	 *            Quantidade de casas decimais a serem considerada no trunc.
	 *
	 * @return Valor truncado.
	 */
	public static Double truncateValue(final Double value,
			final TypeDecimal typeDecimal) {
		if (value != null) {
			final String strValueTemp = new BigDecimal(value).toString();

			int indexDecimalTemp = strValueTemp.indexOf(",");

			if (indexDecimalTemp <= 0) {
				indexDecimalTemp = strValueTemp.indexOf(".");
			}

			if (indexDecimalTemp <= 0) {
				indexDecimalTemp = strValueTemp.length();
			}

			final String temp = strValueTemp.substring(indexDecimalTemp,
					strValueTemp.length());

			NumberFormat dc = new DecimalFormat("#######0.000");

			if (typeDecimal != null) {
				switch (typeDecimal) {
				case ONE_DECIMAL: {
					dc = new DecimalFormat("#######0.00");
					break;
				}
				case TWO_DECIMAL: {
					dc = new DecimalFormat("#######0.000");
					break;
				}
				case FOUR_DECIMAL: {
					dc = new DecimalFormat("#######0.00000");
					break;
				}
				case FIVE_DECIMAL: {
					dc = new DecimalFormat("#######0.000000");
					break;
				}
				case SEVEN_DECIMAL: {
					dc = new DecimalFormat("#######0.00000000");
					break;
				}
				}
			}

			// String strValue = dc.format(value);

			String strValue = String.format("%.10f", value);

			if (temp != null && temp.length() > 3) {
				strValue = strValue.toString();
			}

			int indexDecimal = strValue.indexOf(",");

			if (indexDecimal <= 0) {
				indexDecimal = strValue.indexOf(".");
			}

			if (indexDecimal <= 0) {
				indexDecimal = strValue.length();
			}

			final StringBuilder valueNew = new StringBuilder();

			valueNew.append(strValue.substring(0, indexDecimal));

			if (indexDecimal < strValue.length()) {
				valueNew.append(".");

				int indexFinal = indexDecimal + 3;

				if (typeDecimal != null) {
					switch (typeDecimal) {
					case ONE_DECIMAL: {
						indexFinal = indexDecimal + 2;
						break;
					}
					case TWO_DECIMAL: {
						indexFinal = indexDecimal + 3;
						break;
					}
					case FOUR_DECIMAL: {
						indexFinal = indexDecimal + 5;
						break;
					}
					case FIVE_DECIMAL: {
						indexFinal = indexDecimal + 6;
						break;
					}
					case SEVEN_DECIMAL: {
						indexFinal = indexDecimal + 8;
						break;
					}
					}
				}

				if (indexFinal >= strValue.length()) {
					indexFinal = strValue.length();
				}

				valueNew.append(strValue
						.substring(indexDecimal + 1, indexFinal));
			}

			if (valueNew.toString().contains("E")) {
				throw new IllegalArgumentException("Valor com hexadecional...."
						+ strValue);
			}

			final Double returnValue = new Double(valueNew.toString());

			return returnValue;
		}

		return 0D;
	}

	/**
	 * Truncar um valor passado com parâmetro, será 0 (zero) caso o valor
	 * passado seja nulo. O valor retornado será com duas casas decimais.
	 *
	 * @param value
	 *            Valor informado.
	 * @param typeDecimal
	 *            Quantidade de casas decimais a serem considerada no trunc.
	 *
	 * @return Valor truncado.
	 */
	public static Double truncateValue(final BigDecimal value,
			final TypeDecimal typeDecimal) {
		if (value != null) {
			final String strValueTemp = value.toString();

			int indexDecimalTemp = strValueTemp.indexOf(",");

			if (indexDecimalTemp <= 0) {
				indexDecimalTemp = strValueTemp.indexOf(".");
			}

			if (indexDecimalTemp <= 0) {
				indexDecimalTemp = strValueTemp.length();
			}

			final String temp = strValueTemp.substring(indexDecimalTemp,
					strValueTemp.length());

			NumberFormat dc = new DecimalFormat("#######0.000");

			if (typeDecimal != null) {
				switch (typeDecimal) {
				case ONE_DECIMAL: {
					dc = new DecimalFormat("#######0.00");
					break;
				}
				case TWO_DECIMAL: {
					dc = new DecimalFormat("#######0.000");
					break;
				}
				case FOUR_DECIMAL: {
					dc = new DecimalFormat("#######0.00000");
					break;
				}
				case FIVE_DECIMAL: {
					dc = new DecimalFormat("#######0.000000");
					break;
				}
				}
			}

			String strValue = dc.format(value);

			if (temp != null && temp.length() > 3) {
				strValue = strValue.toString();
			}

			int indexDecimal = strValue.indexOf(",");

			if (indexDecimal <= 0) {
				indexDecimal = strValue.indexOf(".");
			}

			if (indexDecimal <= 0) {
				indexDecimal = strValue.length();
			}

			final StringBuilder valueNew = new StringBuilder();

			valueNew.append(strValue.substring(0, indexDecimal));

			if (indexDecimal < strValue.length()) {
				valueNew.append(".");

				int indexFinal = indexDecimal + 3;

				if (typeDecimal != null) {
					switch (typeDecimal) {
					case ONE_DECIMAL: {
						indexFinal = indexDecimal + 2;
						break;
					}
					case TWO_DECIMAL: {
						indexFinal = indexDecimal + 3;
						break;
					}
					case FOUR_DECIMAL: {
						indexFinal = indexDecimal + 5;
						break;
					}
					case FIVE_DECIMAL: {
						indexFinal = indexDecimal + 6;
						break;
					}
					}
				}

				if (indexFinal >= strValue.length()) {
					indexFinal = strValue.length();
				}

				valueNew.append(strValue
						.substring(indexDecimal + 1, indexFinal));
			}

			if (valueNew.toString().contains("E")) {
				throw new IllegalArgumentException("Valor com hexadecional...."
						+ strValue);
			}

			final Double returnValue = new Double(valueNew.toString());

			return returnValue;
		}

		return 0D;
	}

	/**
	 * Truncar um valor passado com parâmetro, será 0 (zero) caso o valor
	 * passado seja nulo. O valor retornado será com duas casas decimais.
	 *
	 * @param value
	 *            Valor informado.
	 *
	 * @return Valor truncado.
	 */
	public static Double truncateValue(final Double value) {
		return truncateValue(value, TypeDecimal.TWO_DECIMAL);
	}

	public enum TypeDecimal {
		ONE_DECIMAL, TWO_DECIMAL, FOUR_DECIMAL, FIVE_DECIMAL, SEVEN_DECIMAL;
	}

	public static void main(String[] args) {

		Double valor = new Double("25.53");

		Double percentual = new Double("20.00");

		Double valorExtra = valor * percentual / 100;
		
		System.out.println("Valor original: "+valorExtra);

		Double arredondarValor = arredondarValorTaxaExtra(valorExtra);

		System.out.println("Valor: " + arredondarValor);

		Double valor2 = new Double("25.51");

		Double percentual2 = new Double("20.00");

		Double valorExtra2 = valor2 * percentual2 / 100;
		
		System.out.println("Valor original: "+valorExtra2);

		Double arredondarValor2 = arredondarValorTaxaExtra(valorExtra2);

		System.out.println("Valor: " + arredondarValor2);

		Double valor3 = new Double("25.54");

		Double percentual3 = new Double("20.00");

		Double valorExtra3 = valor3 * percentual3 / 100;
		
		System.out.println("Valor original: "+valorExtra3);

		Double arredondarValor3 = arredondarValorTaxaExtra(valorExtra3);

		System.out.println("Valor: " + arredondarValor3);

		Double valor4 = new Double("25.50");

		Double percentual4 = new Double("20.00");

		Double valorExtra4 = valor4 * percentual4 / 100;
		
		System.out.println("Valor original: "+valorExtra4);

		Double arredondarValor4 = arredondarValorTaxaExtra(valorExtra4);

		System.out.println("Valor: " + arredondarValor4);

		Double valor5 = new Double("25.52");

		Double percentual5 = new Double("20.00");

		Double valorExtra5 = valor5 * percentual5 / 100;
		
		System.out.println("Valor original: "+valorExtra5);

		Double arredondarValor5 = arredondarValorTaxaExtra(valorExtra5);

		System.out.println("Valor: " + arredondarValor5);

		Double valor6 = new Double("25.525");

		Double percentual6 = new Double("20.00");

		Double valorExtra6 = valor6 * percentual6 / 100;
		
		System.out.println("Valor original: "+valorExtra6);

		Double arredondarValor6 = arredondarValorTaxaExtra(valorExtra6);

		System.out.println("Valor: " + arredondarValor6);

		Double roundValue = truncateValue(new Double("17000.8499874"),
				TypeDecimal.ONE_DECIMAL);

		System.out.println(roundValue);

		Double roundValue2 = truncateValue(new Double("0.00005"),
				TypeDecimal.ONE_DECIMAL);

		System.out.println(roundValue2);

		Double roundValue3 = arredondarValor(new Double("2222222.677"));

		System.out.println(roundValue3);

		Double roundValue4 = arredondarValor(new Double("2222222.6"));

		System.out.println(roundValue4);
	}

	/**
	 * 
	 */
	private static final Locale sBRAZIL = new Locale("pt", "BR");

	/**
	 * 
	 */
	private static final DecimalFormatSymbols sREAL = new DecimalFormatSymbols(
			sBRAZIL);

	/**
	 * 
	 */
	public static final DecimalFormat sMONEY_BRAZIL = new DecimalFormat(
			"###,###,##0.00", sREAL);

	/**
	 * 
	 * @param value
	 * @param money
	 * @return
	 */
	public static String formatMoney(Double value, DecimalFormat money) {
		return money.format(value);
	}

	/**
	 * 
	 * @param value
	 * @return
	 */
	public static String formatMoney(Double value) {
		DecimalFormat money = sMONEY_BRAZIL;

		return money.format(value);
	}

	public static Double arredondarValor(Double value) {
		DecimalFormat df = new DecimalFormat("###########.##");
		df.setRoundingMode(RoundingMode.UP);

		String format = df.format(value);

		format = format.replace(",", ".");

		return truncateValue(new Double(format), TypeDecimal.TWO_DECIMAL);
	}

	public static Double arredondarValorTaxaExtra(Double value) {

		String format = String.format("%.5f", value);

		format = format.replace(",", ".");

		Double novoValor = new Double(format);

		BigDecimal bigDecimal = new BigDecimal(novoValor).setScale(2,
				RoundingMode.HALF_UP);

		return truncateValue(bigDecimal.doubleValue(), TypeDecimal.TWO_DECIMAL);
	}

}
